/**
 * The class calculates the cosine similarity between the query 
 * and all document vectors, and then tries to put all results
 * into one instance of DocumentHits. 
 */
package qy.course.cse494.ir;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

/**
 * @author qyan
 *
 */
public class DocumentSearch
{
	// input variable
	DocumentIndex _doc_index = null;
	
	// intermediate variables
	Map<Integer, Float> _hit_doc_weight_map = new HashMap<Integer, Float>();
	
	// results
	DocumentHits _doc_hits = new DocumentHits();
	
	// stats
	boolean is_testing = true;
	int _results_num = 0;
	Set<Integer> _hits_doc_hashcode = new HashSet<Integer>();
	
	/**
	 * Default constructor
	 * @param index
	 */
	public DocumentSearch(DocumentIndex index)
	{
		_doc_index = index;
	}
	
	public void clear()
	{
		_hit_doc_weight_map.clear();
		_doc_hits.clear();
	}
	
	public DocumentHits search(DocumentQuery query, int top_k)
	{
		_doc_hits.set_hits_size(top_k);
		return search(query);
	}
	
	/**
	 * The interface to search all matching documents for the query.
	 * @param query
	 * @return
	 */
	public DocumentHits search(DocumentQuery query)
	{
		clear();
		// first, construct the query vector
		Vector<String> keyword_list = (Vector<String>) query.get_keyword_list();
		for(String cur_keyword : keyword_list)
		{
			Map<Integer, Float> doc_weight_index = _doc_index.get_doc_weight_indices_of_term(cur_keyword.toLowerCase());
			if(doc_weight_index == null)
			{
				continue;
			}
			//
			for(Integer cur_doc_id : doc_weight_index.keySet())
			{
				float cur_weight = doc_weight_index.get(cur_doc_id);
				if(_hit_doc_weight_map.containsKey(cur_doc_id))
				{
					cur_weight += _hit_doc_weight_map.get(cur_doc_id);
				}
				_hit_doc_weight_map.put(cur_doc_id, cur_weight);
			}
		}
		// be careful, maybe the cost of division is not so big!!!
		_results_num = 0;
		double norm_value_of_query = Math.sqrt(keyword_list.size());
		for(Integer cur_doc_id : _hit_doc_weight_map.keySet())
		{
			double cost = _hit_doc_weight_map.get(cur_doc_id);
			double norm_value_of_doc_weight = _doc_index.get_norm_value_of_doc_weight(cur_doc_id);
			_doc_hits.add_hit(cur_doc_id, cost/(norm_value_of_doc_weight*norm_value_of_query));
			++_results_num;
			if(is_testing)
			{
				_hits_doc_hashcode.add(_doc_index.get_doc_name(cur_doc_id).hashCode());
//				System.out.print(_doc_index.get_doc_name(cur_doc_id)+" :: ");
//				System.out.println(_doc_index.get_doc_name(cur_doc_id).hashCode());
			}
		}
		
		//
		return _doc_hits;
	}

	/**
	 * @return the _doc_hits
	 */
	public DocumentHits get_hits()
	{
		return _doc_hits;
	}
	
	public int get_results_size()
	{
		return _results_num;
	}
	
	public Set<Integer> get_hits_doc_hashcode()
	{
		return _hits_doc_hashcode;
	}
	
}
